perm filename GENFUN.TEX[CLS,LSP] blob sn#831470 filedate 1986-12-26 generic text, type C, neo UTF8
COMMENT āŠ—   VALID 00003 PAGES
C REC  PAGE   DESCRIPTION
C00001 00001
C00002 00002				    Generic Functions
C00016 00003	Possible Extensions to the Object System
C00031 ENDMK
CāŠ—;
			    Generic Functions

Informally, methods are functions whose applicability is restricted to
arguments that are instances of specific classes.  For a method, each
required formal parameter may have a class associated with it such that
that method will be invoked only if the required actual parameters are
instances of those classes.

In many traditional object-oriented programming systems, objects carry
behavior with themselves, so that applying a function to an object in
functional programming terms corresponds to sending a message to that
object where the message is a request to perform the behavior associated
with the desired function.  For example, whereas one might have written
\begintt
(print <object>)
\endtt
\noindent in Lisp, one might write
\begintt
(send :print <object>)
\endtt
\noindent in a traditional object-oriented system.

The simple message-passing model becomes strained, or even breaks down, when
one wishes to apply a function to two or more objects, because a message
can be sent to only one object. Generic functions solve this problem by
associating behavior with a set of objects. 

A {\bit generic function} is a function that contains or encompasses a
number of {\bit methods}. The required formal parameters of each method
have an associated class specifier, and the method expects to be invoked
only on arguments that satisfy these class specifications. The purpose of
the generic function is to provide the object that contains all methods
that provide the pieces of code that defines the behavior of the generic
function. Because functions can have names associated with them in
Common Lisp, the same naming conventions apply to generic functions.

A generic function is responsible for selecting a method or methods, given
a set of supplied arguments.  Normally, this selection process examines
the required arguments and selects the method whose class specifiers match
those of the supplied arguments. When the generic function specifies a
method combination type, some set of methods is selected, and an
application order and a result combination procedure are applied.

The behavior of objects in \CLOS\ is determined by the structure of the
class lattice: each object in the system is an instance of a class, and the
classes are located in a superclass/subclass lattice. The structure of
an object is determined by the class of which it is an instance and by the
classes of which the objects's class is a subclass.

Because the classes form a lattice, each method can be thought of as being
associated with a set of nodes in the lattice. Also, because methods can
be defined at different times and in different locations (in different files),
methods can be thought of as a `distributed' definition of a generic function.

Because generic functions are properly termed `functions,' there is a
benefit to making them act like functions as much as possible. Therefore,
the distributed nature of generic function definition does not require a
corresponding distributed nature for generic function implementation.

In this standard, therefore, we have adopted the notion of a generic
function as a first-class object.  Generic functions, as described in this
specification, are a departure from the usual intuitive notions of how
methods are represented.  This departure, though, enables us to obtain
both the convenience benefits of distributed method definition along with
the clarity of first-class generic functions.

There are three things that the concept of generic functions buys us:

\numitem{1.} The ability to spread the definition of a generic function
among the places where the partial definitions make the most
sense.  This is accomplished by placing DEFMETHODs in the
places where the relevant classes are defined, for example.

\numitem{2.} The ability to abstract the definition of a generic function
into parts (methods) that are conceptually independent.  This
is accomplished by splitting the definition of a generic
function into independent parts where each part is the partial
function definition for a particular set of classes - each part
is a method.  This leads to a new modularization technique.

\numitem{3.} The separation of the inheritance of behavior from placement of
code. Generic functions select methods based on the structure
of the class lattice, but the generic functions are not
constrained to be stored within that lattice.

			    Generic Functions

There is a new type of first-class object, called a `generic function.'
It can be FUNCALLed and APPLYed exactly as Common Lisp functions can be.
When the function cell of a symbol contains a generic function, we say
that the symbol, call it S, `names' the generic function and that the
generic function is associated with the name, S. This is exactly as
things are in Common Lisp with respect to functions. Using MAKE-GENERIC
it is possible to create a generic function not associated with any
symbol.

Generic functions have internal structure. This internal structure
includes the argument list, the argument precedence order, method
combination information, and `methods.'  Not required in that internal
structure is a `name' for the generic function.  A generic function, in
some implementations, might have a name as part of itself but only as an
informational device for use by programming environment tools. The correct
functioning of generic function cannot depend on that name.  When a
generic function is invoked, it invokes and combines some subset of the
methods. Which methods are invoked and how their results are combined
depends on the classes of the arguments supplied to the generic function
and on the method combination type of the generic function.

Methods are objects with internal structure and are properly called
`method objects.'  The term `method' is commonly used to refer to method
objects.  Method objects include as parts a function, called the `method
function,' and some other user-visible information.  One such piece of
user-visible information is a pointer back to the generic function of
which the method is part.

Methods are associated with generic functions, but are not associated
directly with any names except in an informational sense - the correct
functioning of a method cannot depend on its name.  If a method is part of
a generic function which is associated with a symbol, S, we say that the
method is `defined for S.'  ADD-METHOD and GET-METHOD add methods to and
retrieve method objects from, respectively, generic functions. DEFMETHOD
adds a method to the generic function associated with the symbol that is
the first argument of DEFMETHOD.

Method objects are functions. GET-METHOD returns a method object, which
can be FUNCALLed and APPLYed.

(typep <generic-function> 'function) 

where <generic-function> is a generic function returns T.

(typep <method-object> 'function)

where <method-object> is a method object returns T.

A method function is simply a Common Lisp function.

Generic functions are self-contained objects.  The parts of generic
functions are not spread out in the heap, in tables, or in the class
lattice: The parts are contained in the generic function. Pointers to
generic functions might appear in various places for the proper function
of tools.  One place is the class lattice, which defines the inheritance
structure on which the operation of generic functions depends. [Note:
an implementation is free to spread the definition wherever it likes
as long as it maintains the illusion of generic functions as first-class
objects.]

For example, environmental tools for associating methods with classes are
desirable.  These tools will enable us to browse through a class lattice
and display all methods that operate on instances of the classes being
browsed.  To do this, the tool must be able to determine for each class
the generic functions that operate on that class.  In the case where a
generic function is associated with a symbol, it is nice to display that
symbol as the name of the generic function (that is, as the operator).

FMAKUNBOUND can disrupt the correct functioning of this tool.

FMAKUNBOUND, when applied to a symbol with which a generic function is
associated, removes the generic function definition from the function cell
of the symbol.  FMAKUNBOUND cannot cause generic functions to behave
inconsistently with respect to their invocation semantics. 
[(SETF (SYMBOL-FUNCTION ...) ...) also cannot disrupt invocation semantics.]

Possible Extensions to the Object System

This section describes four additions to the basic object system.  These
additions are still under discussion.

There are three sorts of non-named-by-symbol generic function forms that
need to be defined: pure anonymous, LABELS equivalent, and FLET
equivalent. There is probably only one reasonable way to define anonymous
generic functions:

#'(generic-lambda <method-spec>*)

where <method-spec> is

	(<specialized lambda list> . <body>)

For example:

#'(generic-lambda
   (((x1 c1)(x2 c2)) (foo x1 x2))
   (((x1 c3) (x2 c4)) (baz x1 x2)))

The other facets of the generic function are defaulted. The programmer may
wish to modify them.  These facets are:  argument-precedence order,
generic-function-class, interface, method-arguments, method-class, and
method-combination-type.


The two remaining cases are for LABELS and FLET equivalents.
GENERIC-FUNCTION-LABELS corresponds to LABELS and GENERIC-FLET corresponds
to FLET. These names are negotiable.

For each of GENERIC-FUNCTION-LABELS and GENERIC-FLET there are two
possible styles, called the modular and the distributed styles. In the
modular style:

(generic-function-labels (<generic-function-spec>*) . <body>)

where <generic-function-spec> is

(<generic-function-name> <method-spec>*)

where the <method-spec> is as above. Here is an example:

(generic-function-labels
 ((gf1
   ;;; First method on gf1
   (((x1 c1) (x2 c2)) (when (recursivep x1) (gf1 (f1 x1) (f2 x2))))
   ;;; Second method on gf1
   (((x1 c3) (x2 c3)) (when (recursivep x1) (gf2 (f3 x1) (f4 x2)))))
  (gf2
   ;;; First method on gf2
   (((x1 c4)(x2 c5)) (gf1 (f5 x1) (f6 x2)))
   ;;; Second method on gf2
   (((x1 c6)(x2 c7)) (gf2 (f7 x1)(f8 x2)))))
 ;;; Now we use these guys
 (gf1 x1 y1) ... (gf2 xn yn))

The distributed style looks like this:

(generic-function-labels (<named-method-spec>*) . <body>)

where <named-method-spec> is

(<generic-function-name> <method-spec>)

Here is an example:

(generic-function-labels
 ;;; First method on gf1
 ((gf1 ((x1 c1) (x2 c2)) (when (recursivep x1) (gf1 (f1 x1) (f2 x2))))
  ;;; Second method on gf1
  (gf1 ((x1 c3) (x2 c3)) (when (recursivep x1) (gf2 (f3 x1) (f4 x2))))
  ;;; First method on gf2
  (gf2 ((x1 c4)(x2 c5)) (gf1 (f5 x1) (f6 x2)))
  ;;; Second method on gf2
  (gf2 ((x1 c6)(x2 c7)) (gf2 (f7 x1)(f8 x2))))
 ;;; Now we use these guys
 (gf1 x1 y1) ... (gf2 xn yn))

The GENERIC-FLET admits both modular and distributed styles, which
I won't show.

I'm not sure which I favor. Of course, one can ADD-METHOD to any of
these generic functions.

I made an assumption when devising these, which was that it is not
possible for a method to call another method without the intervention
of a generic function.  In this case, a hairier reference scheme is
needed.

			-rpg-

There is a second sort of `local' definition of methods that could make
sense - it is the one to which Gregor alluded in his message about my
anonymous generic function proposal. Suppose that a set of methods on the
symbol, FOO, has been defined. In a dynamic context the user might want
to temporarily extend FOO. I will use the name DFLET-METHOD; the user can
write:

(DFLET-METHOD ((FOO ((X C)) ...)) <form>)

and temporarily extend the generic function FOO to have this new method
associated with it during the execution of <form>. This, also, is a
reasonable programming methodology. I was curious about why Gregor thought
I meant something like DFLET-METHOD in my lexical generic function
proposal, even though I think my proposal was relatively clear on my
intention. I believe it is because Gregor thinks in terms of methods and
not in terms of generic functions.